package com.dhcc.utils.object;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * 属性调用器
 * @author hibean@qq.com 2017年7月3日
 *
 */
interface Invoker {

	/**
	 * 执行获得
	 * @return
	 */
	Object invokeGet(Object target);
	
	/**
	 * 执行设置
	 * @param target
	 * @param value
	 */
	void invokeSet(Object target, Object value);
	
	Class<?> getParameterType();
	
	/**
	 * 获取返回类型
	 * @return
	 */
	Class<?> getReturnType();
}

/**
 * 调用器职责链
 * @author hibean@qq.com 2017年8月2日
 *
 */
class ChainInvoker implements Invoker{
	private Invoker next;
	private Invoker cur;
	public ChainInvoker(Invoker cur, Invoker next) {
		this.cur = cur;
		this.next = next;
	}
	@Override
	public Object invokeGet(Object target) {
		Object obj = cur.invokeGet(target);
		return next.invokeGet(obj);
	}

	@Override
	public void invokeSet(Object target, Object value) {
		Object obj = cur.invokeGet(target);
		next.invokeSet(obj, value);
	}

	@Override
	public Class<?> getParameterType() {
		return next.getParameterType();
	}
	@Override
	public Class<?> getReturnType() {
		return cur.getReturnType();
	}
	
}

class PojoInvoker implements Invoker{
	private Method method;
	public PojoInvoker(Method method) {
		this.method = method;
	}
	@Override
	public Object invokeGet(Object target) {
		try {
			return method.invoke(target);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	@Override
	public void invokeSet(Object target, Object value) {
		try {
			method.invoke(target, value);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	@Override
	public Class<?> getParameterType() {
		if(method.getParameterTypes().length==0){
			throw new RuntimeException("不支持返回类型");
		}
		return  method.getParameterTypes()[0];
	}
	@Override
	public Class<?> getReturnType() {
		return method.getReturnType();
	}
}
class MapInvoker implements Invoker{
	private String property;

	public MapInvoker(String property) {
		this.property = property;
	}
	@Override
	public Object invokeGet(Object target) {
		return ((Map)target).get(property);
	}
	@Override
	public void invokeSet(Object target, Object value) {
		((Map)target).put(property, value);
	}
	@Override
	public Class<?> getParameterType() {
		return Object.class;
	}
	@Override
	public Class<?> getReturnType() {
		return Map.class;
	}
	
}
